
                /*********************************************
                **                                          **
                **                                          **
                **                 cs.4.C                   **
                **                                          **
                **                                          **
                *********************************************/
                /*********************************************
                **                                          **
                **         Author Jean-Marc Adamo           **
                **       Copyright (C) 1997-2008 JMA        **
                *********************************************/
/*
** testsyncSR4.C
** testing Sdf::alt with composite chan utilization:
** ChanL, ChanR, ChanRD<T>
** Needs at least 3 processes
*/

#include "arch.h"

//user program
Global_id gid1;
Global_id gid2;
Global_id gid3;
Coll_id cid;

void init_gid(int, char **){
   gid1.set();
   gid2.set();
   gid3.set();
   cid.set();
   fprintf(Sdf::trace, "node%d: gid1.tag=%d, gid2.tag=%d, gid3.tag=%d, cid.tag=%d\n",
           Sdf::PROC_ID, gid1.get(), gid2.get(), gid3.get(), cid.get());
   fflush(Sdf::trace);
}

ChanRD<int> *chan;
ChanL *chan1;
ChanRD<int> *chan2_0;
ChanR *chan2_1;


class Sender: public S_Thread{

   public:

        Sender()
                : S_Thread((Smf0_ptr)&Sender::body){}


        void body(){


           fprintf(Sdf::trace, "node %d, in proc %d before for loop\n",
                   Sdf::PROC_ID, 0);
           fflush(Sdf::trace);

           int msg;

           for(int j=0; j<2; j++){

                msg = j+Sdf::PROC_ID;
                chan->send(msg);

                fprintf(Sdf::trace, "node %d, in proc %d after send chan, j = %d\n",
                        Sdf::PROC_ID, 0, j);
                fflush(Sdf::trace);
           }

           msg = 50+Sdf::PROC_ID;
           chan2_0->send(msg);

           fprintf(Sdf::trace, "node %d, in proc %d after send chan2_0.0\n",
                   Sdf::PROC_ID, 0);
           fflush(Sdf::trace);

           chan2_1->send();

           fprintf(Sdf::trace, "node %d, in proc %d after send chan2_1.0\n",
                   Sdf::PROC_ID, 0);
           fflush(Sdf::trace);

           msg = 100+Sdf::PROC_ID;
           chan2_0->send(msg);

           fprintf(Sdf::trace, "node %d, in proc %d after send chan2_0.1\n",
                   Sdf::PROC_ID, 0);
           fflush(Sdf::trace);

           chan2_1->send();

           fprintf(Sdf::trace, "node %d, in proc %d after send chan2_1.1\n",
                   Sdf::PROC_ID, 0);
           fprintf(Sdf::trace, "node %d, in proc %d sender ends up\n",
                         Sdf::PROC_ID, 0);
           fflush(Sdf::trace);

    }
};


class Isender: public S_Thread{

   public:

        Isender()
                : S_Thread((Smf0_ptr)&Isender::body){}

        void body(){

           fprintf(Sdf::trace, "node %d, in proc %d before send chan1\n",
                         Sdf::PROC_ID, 1);
           fflush(Sdf::trace);

           chan1->send();

           fprintf(Sdf::trace, "node %d, in proc %d after send chan1\n",
                         Sdf::PROC_ID, 1);
           fflush(Sdf::trace);
    }
};


class Receiver: public S_Thread{

   public:

        int msg;

        Receiver()
                : S_Thread((Smf0_ptr)&Receiver::body){}

        void body(){

          fprintf(Sdf::trace, "node %d, in proc %d before for loop\n",
                  Sdf::PROC_ID, 2);
          fflush(Sdf::trace);

          for(int j=0; j<2; j++){

            chan->recv(msg);

            fprintf(Sdf::trace, "node %d, in proc %d after recv chan, j = %d, msg = %d\n",
                    Sdf::PROC_ID, 2, j, msg);
            fflush(Sdf::trace);
           }

           chan2_0->recv(msg);

           fprintf(Sdf::trace, "node %d, in proc %d after recv chan2_0, msg = %d\n", 
                   Sdf::PROC_ID, 2, msg);
           fflush(Sdf::trace);

           chan2_1->recv();

           fprintf(Sdf::trace, "node %d, in proc %d after recv chan2_1\n",
                   Sdf::PROC_ID, 2);
           fflush(Sdf::trace);

           Alts *alt_table[3];
           alt_table[0] =  new AltRDrecv<int>
                                   (chan2_0, 
                                    this,
                                    (Smf2_ptr)&Receiver::alt_body,
                                    0,
                                    msg);

           alt_table[1] =  new AltR(chan2_1, 
                                    this,
                                    (Smf2_ptr)&Receiver::alt_body,
                                    0);

           alt_table[2] =  new AltL(chan1,
                                    this,
                                    (Smf2_ptr)&Receiver::alt_body,
                                    0);


           AltCtrl *alt_ctrl = new AltCtrl(3, alt_table);
           for(int i = 0; i< 3; i++){
              Sdf::alt(alt_ctrl);
           }

           delete alt_table[0], delete alt_table[1], delete alt_table[2];
           delete alt_ctrl;

           fprintf(Sdf::trace, "node %d, in proc %d receiver ends up\n",
                   Sdf::PROC_ID, 2);
           fflush(Sdf::trace);
        }



       void alt_body(int rank, void *arg_ptr){

            fprintf(Sdf::trace, "node %d, in proc %d in alt_body, rank = %d\n",
                           Sdf::PROC_ID, 2, rank);
            if(rank == 1){
                fprintf(Sdf::trace, "node %d, in proc %d in alt_body.%d, msg = %d\n",
                           Sdf::PROC_ID, 2, rank, msg);
            }
            if(rank == 2){
             fprintf(Sdf::trace, "node %d, in proc %d in alt_body, rank = %d\n",
                           Sdf::PROC_ID, 2, rank);
            }
            fflush(Sdf::trace);
       }
};

class Root_proc: public Thread{

   public:
        Root_proc()
                : Thread((Tmf0_ptr)&Root_proc::body){}

        void body(){

            fprintf(Sdf::trace, "node %d, in Root_proc::body1\n", Sdf::PROC_ID);

            chan = new ChanRD<int>(gid1, (Sdf::PROC_ID+1)%Sdf::PROC_NB);
            chan2_0 = new ChanRD<int>(gid2, (Sdf::PROC_ID+1)%Sdf::PROC_NB);
            chan2_1 = new ChanR(gid3, (Sdf::PROC_ID+2)%Sdf::PROC_NB);

            Sdf::barrier(cid);
                //synchronizes chan construction(no longer
                //necessary starting from version 5)

            chan1 = new ChanL;

            Sender * sender = new Sender;
            Receiver * receiver = new Receiver;
            Isender * isender = new Isender;

            /*####*/
            fprintf(Sdf::trace, "node %d, chan = %d, chan2[0] = %d, chan2[1] = %d, sender = %d, receiver = %d\n",
            Sdf::PROC_ID, chan, chan2_0, chan2_1, sender, receiver);

            fprintf(Sdf::trace, "node %d, in Root_proc::body2\n", Sdf::PROC_ID);
            fflush(Sdf::trace);

            S_Thread *proc_tabl[3] = {sender, isender, receiver};
            int pri[3] = {1, 1, 1};
            par(3, proc_tabl, pri);

            fprintf(Sdf::trace, "node %d, in Root_proc::body3\n", Sdf::PROC_ID);

            Sdf::barrier(cid);
                     //synchronizes chan destruction
            delete chan;
            delete chan1;
            delete chan2_0;
            delete chan2_1;
            delete sender;
            delete isender;
            delete receiver;
    }
};

//end of user program


MAIN(Root_proc, init_gid, Sdf::empty, Sdf::empty)


